import os
import socket
import time


class Client:
    """
    Client 类，用于与服务器进行通信

    Attributes:
        server_address (tuple): 服务器的地址和端口
        data_size (int): 数据大小
        client_socket (socket.socket): 客户端套接字
        ShowMessage (list): 存储服务器返回的消息

    Methods:
        __init__(self, server_address, data_size): 初始化客户端
        send_command(self, command): 向服务器发送命令并接收响应
        close(self): 关闭客户端套接字
        ShowLs(self): 显示服务器返回的文件列表
    """

    def __init__(self, server_address, data_size):
        """
        初始化客户端

        Args:
            server_address (tuple): 服务器的地址和端口
            data_size (int): 数据大小
        """
        # 初始化服务器地址属性
        self.server_address = server_address
        # 初始化数据大小属性
        self.data_size = data_size
        # 创建客户端套接字
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 初始化存储服务器返回消息的列表
        self.ShowMessage = None
        # 收到的是文件还是列表
        self.IsFile = None
        # 服务器的响应
        self.response = None
        # 文件的路径
        self.FilePath = None
        # 当前文件夹路径
        self.SavePath = None
        #当前文件信息
        self.FileMessage = None
        #发送的信息
        self.command=None

    def send_command(self, command):
        """
        向服务器发送命令

        Args:
            command (str): 要发送的命令

        Returns:
            str: 服务器的响应
        """
        self.command = command
        self.client_socket.sendall(command.encode('gbk'))
        #print(self.response)
    def GetResponse(self):
        """
        接收数据
        """
        self.response = self.client_socket.recv(self.data_size)

        #print(self.response)
    def close(self):
        """
        关闭客户端套接字
        """
        self.client_socket.close()

    def ConnectServer(self):
        """
        连接到服务器
        """
        self.client_socket.connect(self.server_address)

    def ShowLs(self):
        """
        显示服务器返回的文件列表
        """
        for i,data in enumerate(self.ShowMessage):
            print(f"num:{i} name:{data[0]} size:{data[1]}")




    def DoIsFile(self):
        try:  # 尝试解析服务器的响应为文件列表
            self.ShowMessage = eval(self.response.decode('gbk'))
            if self.ShowMessage[0][0]=='wj':
                self.IsFile = True
                return True
            else:
                self.IsFile = False
                return False
        except Exception as e:  # 解析失败，响应可能是文件
            print("判定为文件夹有错，可能是文件")
            print(e)
            self.IsFile = True
            return True

    def GetFile(self):
        """
        接收文件
        """
        self.FilePath = self.ShowMessage[1][0]
        self.FilePath = self.FilePath.replace('F:', str(self.SavePath))
        total_size=self.ShowMessage[1][1]
        self.client_socket.setblocking(False)#非阻塞
        # 检查路径是否存在，不存在就创建
        if not os.path.exists(os.path.dirname(self.FilePath)):
            print("路径不存在，创建路径", os.path.dirname(self.FilePath))
            os.makedirs(os.path.dirname(self.FilePath))

        with open(self.FilePath, 'wb') as file:
            received_size = 0
            while True:
                data=None
                try:
                    #time.sleep(0.1)
                    data = self.client_socket.recv(1024*1024)
                except socket.error as e:
                    # 非阻塞模式下，recv可能会抛出socket.error异常
                    if e.errno != socket.EWOULDBLOCK:
                        # 如果不是因为没有数据可读而抛出的异常，打印错误信息
                        print("Socket error:", e)
                        client.close()
                        break

                if data==None and (received_size==total_size):# 接收完成
                    break
                elif data!=None and received_size!=total_size:# 接收中
                    file.write(data)
                    received_size += len(data)
                    percent = (received_size / total_size) * 100 if total_size > 0 else 0
                    print(f"\rReceiving {self.FilePath}: {percent:.2f}%", end='')
                else:# 接收失败,但是还有数据没传完
                    time.sleep(0.1)
                    continue
            print("文件接受成功")
            self.client_socket.setblocking(True)  # 阻塞


    def reconnection(self):
        """
        重新连接
        """
        pass

    def Main(self,SavePath):
        """
        主函数
        """
        self.SavePath=SavePath
        self.ConnectServer()  # 连接到服务器
        while True:
            command = input("请输入命令 (ls,../, pwd, wq): ")  # 获取客户命令
            self.send_command(command)  # 发送命令并获取响应
            self.GetResponse()
            self.DoIsFile()
            if self.IsFile:  # 响应是文件
                self.GetFile()
            else:
                self.ShowLs()

            if self.command == "wq":
                break


# 示例用法
if __name__ == "__main__":
    server_address = ('cn-sz-yd-plustmp2.natfrp.cloud', 10620)  # 服务器地址和端口
    data_size = 4096  # 数据大小
    SavePath='./pcdata'

    client = Client(server_address, data_size)
    client.Main(SavePath)
